/**
 * @author 清翔电子:03
 * @author McDanci
 *
 * @todo
 * 【编写时间】： 2016年02月15日
 * 【编译环境】： Keil μVisio3
 * 【使用说明】： 正确接上LCD1602液晶并调节好对比度
 */
#include <STC/STC89C5xRC.H>

typedef unsigned char uchar;
typedef unsigned int uint;

#define LCD_DB P0 // LCD1602并行数据总线

#define DSEG_SEG P26 // 数码管段选
#define DSEG_POS P27 // 位选

#define LCD_RS P35
#define LCD_RW P36
#define LCD_ENABLE P34

/**
 * LCD模块忙时等候回圈
 */
void busy_hook()
{
	uchar busy; // TODO

	LCD_DB = 0xff; // 复位：拉高数据总线的电平
	LCD_RS = 0;
	LCD_RW = 1; // 拉高：读

	do
	{
		LCD_ENABLE = 1; // 使能，上升沿跳变
		busy = LCD_DB;	// 读busy flag状态
		LCD_ENABLE = 0; // 去使能，以待下回上升沿跳变
	} while (busy & 0x80);
}

/**
 * 写一字节命令
 * @param int cmd 待写入的指令 TODO
 */
void send_cmd(uchar cmd)
{
	busy_hook();

	LCD_RS = 0;
	LCD_RW = 0;

	LCD_DB = cmd;

	LCD_ENABLE = 1; // 数据传输至LCD_DB
	LCD_ENABLE = 0;
}

/**
 * 写一字节数据
 * @param int cmd 待写入的数据 TODO
 */
void send_data(uchar data)
{
	busy_hook();

	LCD_RS = 1;
	LCD_RW = 0;

	LCD_DB = data;

	LCD_ENABLE = 1;
	LCD_ENABLE = 0;
}

/*=================================================
*函数名称：LCD1602_Dis_OneChar
*函数功能：在指定位置显示一个字符
*调用：LCD1602_Write_Cmd(); send_data();
*输入：x：要显示的横坐标取值0-40，y：要显示的行坐标取值0-1（0为第一行,1为第二行）
		dat：需要显示的数据以ASCLL形式显示
=================================================*/
void LCD1602_Dis_OneChar(uchar x, uchar y, uchar dat)
{
	if (y)
		x |= 0x40;
	x |= 0x80;
	send_cmd(x);
	send_data(dat);
}

/*=================================================
*函数名称：LCD1602_Dis_Str
*函数功能：在指定位置显示字符串
*调用：LCD1602_Write_Cmd(); send_data();
*输入：x：要显示的横坐标取值0-40，y：要显示的行坐标取值0-1（0为第一行,1为第二行）
		*str：需要显示的字符串
=================================================*/
void LCD1602_Dis_Str(uchar x, uchar y, uchar *str)
{
	if (y)
		x |= 0x40;
	x |= 0x80;
	send_cmd(x);
	while (*str != '\0')
	{
		send_data(*str++);
	}
}

void lcd_init()
{
	// 关闭数码管
	DSEG_SEG = 0;
	DSEG_POS = 0;

	LCD_ENABLE = 0;

	send_cmd(0x38); // 16 * 2
	send_cmd(0x0c); // 启用：显示光标，光标不闪烁
	send_cmd(0x06); // 光标（地址指针）移动方式
	send_cmd(0x01); // 清屏
}

/**
 * @todo
 * 【程序功能】： LCD1602显示
 */
void main()
{
	uchar TestStr[] = {"Welcome!"};

	lcd_init();

	LCD1602_Dis_Str(0, 0, &TestStr[0]); //显示字符串
	LCD1602_Dis_OneChar(10, 1, 0xff);	//显示一个黑方格
	while (1)
		;
}
